﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;

namespace FerrSimplicity
{
    /// <summary>
    /// This class can be used for creating and converting color to and from different color spaces.
    /// </summary>
    class UtilColor
    {
        readonly static float sqrt3 = (float)Math.Sqrt(3);

        #region Cylindrical Color Spaces
        /// <summary>
        /// Creates a color from Hue/Saturation/Luminance space.
        /// </summary>
        public static Color   HSL  (float aHue, float aSaturation, float aLuminance)
        {
            // HSL is a circle of colors, divided into six slices
            float hue    = ((aHue % 1) * 360.0f) / 60.0f;

            // Calculate the (XY sort of) location of the color within the color slice
            float chroma = (1 - Math.Abs(2 * aLuminance - 1)) * aSaturation;
            float x      = chroma * (1 - Math.Abs(hue % 2 - 1));

            // and pick out the color based on the hue region
            float r = 0, g = 0, b = 0;
            if (hue < 1)
            {
                r = chroma;
                g = x;
            }
            else if (hue < 2)
            {
                r = x;
                g = chroma;
            }
            else if (hue < 3)
            {
                g = chroma;
                b = x;
            }
            else if (hue < 4)
            {
                g = x;
                b = chroma;
            }
            else if (hue < 5)
            {
                r = x;
                b = chroma;
            }
            else
            {
                r = chroma;
                b = x;
            }

            // and factor in the lightness
            float valueMatch = aLuminance - 0.5f * chroma;

            return new Color(r + valueMatch, g + valueMatch, b + valueMatch);
        }
        /// <summary>
        /// Converts an RGB color to a Huse/Saturation/Value space color.
        /// </summary>
        public static Vector3 ToHSV(float aR,   float aG,          float aB        )
        {
            float max        = Math.Max(aR, Math.Max(aG, aB));
            float min        = Math.Min(aR, Math.Min(aG, aB));

            float hue        = (float)Math.Atan2(2 * aR - aG - aB, sqrt3 * (aG - aB));
            float saturation = (max == 0) ? 0 : 1 - (1 * min / max);
            float value      = max;

            return new Vector3(hue, saturation, value);
        }
        /// <summary>
        /// Creates a color from Hue/Saturation/Value space.
        /// </summary>
        public static Color   HSV  (float aHue, float aSaturation, float aValue    )
        {
            // HSV is a hexagon of color, divide the hue into one of the six sectors
            float hue    = ((aHue % 1) * 360.0f) / 60.0f;

            // Calculate the (XY sort of) location of the color within the hexagon slice
            float chroma = aValue * aSaturation;
            float x      = chroma * (1 - Math.Abs(hue % 2 - 1));

            // and pick out the color based on the hue region
            float r = 0, g = 0, b = 0;
            if (hue < 1)
            {
                r = chroma;
                g = x;
            }
            else if (hue < 2)
            {
                r = x;
                g = chroma;
            }
            else if (hue < 3)
            {
                g = chroma;
                b = x;
            }
            else if (hue < 4)
            {
                g = x;
                b = chroma;
            }
            else if (hue < 5)
            {
                r = x;
                b = chroma;
            }
            else
            {
                r = chroma;
                b = x;
            }

            // and factor in the value/saturation
            float valueMatch = aValue - chroma;

            return new Color(r + valueMatch, g + valueMatch, b + valueMatch);
        }
        /// <summary>
        /// Creates a color from Hue/Chroma/Luma space.
        /// </summary>
        public static Color   HCL  (float aHue, float aChroma,     float aLuma     )
        {
            // HCL is a color cube, divided up into 6 faces
            float hue = ((aHue % 1) * 360.0f) / 60.0f;

            // Calculate the XY location of the color within the face
            float x   = aChroma * (1 - Math.Abs(hue % 2 - 1));

            // and pick out the color based on the hue region
            float r = 0, g = 0, b = 0;
            if (hue < 1)
            {
                r = aChroma;
                g = x;
            }
            else if (hue < 2)
            {
                r = x;
                g = aChroma;
            }
            else if (hue < 3)
            {
                g = aChroma;
                b = x;
            }
            else if (hue < 4)
            {
                g = x;
                b = aChroma;
            }
            else if (hue < 5)
            {
                r = x;
                b = aChroma;
            }
            else
            {
                r = aChroma;
                b = x;
            }

            // and factor in the luma
            float lumaMatch = aLuma - (0.3f * r + 0.59f * g + 0.11f * b);

            return new Color(r + lumaMatch, g + lumaMatch, b + lumaMatch);
        }
        #endregion
    }
}
